#if HybridCLR
using HybridCLR;
#endif
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace TCC.Framework
{
    /// <summary>
    /// 程序入口
    /// </summary>
    [DefaultExecutionOrder(-10000)]
    public class ResetHandler : SingletonBehaviourBase<ResetHandler>
    {
        #region 音频
        /// <summary>
        /// 背景音乐播放器
        /// </summary>
        [SerializeField] AudioSource backgroundSource;
        /// <summary>
        /// 其它音乐播放器
        /// </summary>
        [SerializeField] AudioSource otherSource;
        #endregion

        #region UI
        /// <summary>
        /// Canvas
        /// </summary>
        [SerializeField] Transform canvas;
        /// <summary>
        /// 首界面
        /// </summary>
        [SerializeField] string homePage;
        #endregion

        #region 本地化语言
        /// <summary>
        /// 语言资源
        /// </summary>
        [SerializeField]LanguageDate languageDate;
        /// <summary>
        /// 默认语言 （初始化使用的语言）
        /// </summary>
        [SerializeField]Languagel defaultLanguagel=Languagel.Chinese;
        #endregion

        #region 对象池
        /// <summary>
        /// 对象池
        /// </summary>
        [SerializeField] Transform objectPool;
        #endregion

        #region 控制器
        /// <summary>
        /// 主相机
        /// </summary>
        [SerializeField] Camera mainCamera;

        [SerializeField] float moveSpeed;

        [SerializeField] float rotateSpeed;

        [SerializeField] Transform role;

        [SerializeField] float scrollWheelSpeed;

        /// <summary>
        /// 初始的摄像机x轴旋转值
        /// </summary>
        [SerializeField] float initXRotate;
        /// <summary>
        /// 初始的摄像机y轴旋转值
        /// </summary>
        [SerializeField] float initYRotate;
        /// <summary>
        /// 摄像机与角色距离
        /// </summary>
        [SerializeField] float distance;
        /// <summary>
        /// 摄像机与注释目标最小距离
        /// </summary>
        [SerializeField] float minDistance;
        /// <summary>
        /// 摄像机与注释目标最大距离
        /// </summary>
        [SerializeField] float maxDistance;
        /// <summary>
        /// Y轴上最小旋转值或最大旋转值
        /// </summary>
        [SerializeField] float yMinAngleLimit;
        [SerializeField] float yMaxAngleLimit;
        /// <summary>
        /// 是否使用缓动
        /// </summary>
        [SerializeField] bool isNeedDamping;
        /// <summary>
        /// 缓动时长
        /// </summary>
        [SerializeField] float dampingTime;

        /// <summary>
        /// 射线提示框
        /// </summary>
        [SerializeField] RectTransform rayHitRoot;

        /// <summary>
        /// 射线提示文本组件
        /// </summary>
        [SerializeField] UIBehaviour rayHitText;
        #endregion

        #region 输入管理
        /// <summary>
        /// 输入设备类型
        /// </summary>
        [SerializeField] string inputDeviceType;
        /// <summary>
        /// 是否启用输入设备
        /// </summary>
        [SerializeField] bool isEnableInputDevice;
        #endregion

        #region 热更新
        /// <summary>
        /// 是否开启热更
        /// </summary>
        [SerializeField] bool isHotfix;

        /// <summary>
        /// 热更入口
        /// </summary>
        [SerializeField]string updataHandle;

        /// <summary>
        /// 资源下载地址
        /// </summary>
        [SerializeField] string resServerUrl;

        /// <summary>
        ///本地资源存放路径
        /// </summary>
        [SerializeField] string localResFilePath;

        /// <summary>
        ///资源下载器数量
        /// </summary>
        [SerializeField] int downloadRoutinneNum;

        /// <summary>
        /// 资源加载模式
        /// </summary>
        [SerializeField] UpdateMode loadMode;
        #endregion

        public LanguageDate LanguageDate { get => languageDate; }


        #region 管理器
        public UIManager UIMagr { get; private set; }
        public ResourceManager ResMagr { get; private set; }

        public AudioManager AudioMagr { get; private set; }

        public WordManager WordMagr { get; private set; }

        public ReferencePoolManager ReferPoolMagr { get; private set; }

        public DataManager DataMagr { get; private set; }

        public ObjectPoolMananger ObjPoolMagr { get; private set; }

        public EventManager EventMagr { get; private set; }

        public VersionsManager VersionsdMagr { get; private set; }

        public WebNetManager WebNetMagr { get; private set; }

        public InputManager InputMagr { get; private set; }

        public ControllerManager ControllerMagr { get; private set; }
        #endregion

        /// <summary>
        /// 当前场景
        /// </summary>
        public Scene CurrentScene { get; set; }

        private TAction OnUpdate;

        /// <summary>
        /// 获取平台
        /// </summary>
        public static string GetPlatform
        {
            get
            {
#if UNITY_ANDROID
                return "Android";
#elif UNITY_IOS
                return "IOS";
#elif UNITY_STANDALONE_OSX
                return "Mac";
#elif UNITY_STANDALONE_WIN
                return "Windows";
#elif UNITY_WEBGL
                return "WebGL";
#else
                return Application.platform.ToString();
#endif
            }
        }

        /// <summary>
        /// 主摄像机
        /// </summary>
        public Camera MainCamera => mainCamera;

        private InputDeviceBase _currentInputDevice;
        public InputDeviceBase CurrentInputDevice
        {
            get
            {
                if(_currentInputDevice==null)
                {
                    Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().First(p => p.GetType(inputDeviceType) != null);
                    if (assembly != null)
                        _currentInputDevice = assembly.CreateInstance(inputDeviceType) as InputDeviceBase;
                }
                return _currentInputDevice;
            }
        }

        /// <summary>
        /// 射线捕获目标提示框节点
        /// </summary>
        public RectTransform RayHitRoot
        {
            get => rayHitRoot;
            set => rayHitRoot = value;
        }

        /// <summary>
        /// 射线捕获目标提示文本组件
        /// </summary>
        public UIBehaviour RayHitText
        {
            get => rayHitText;
            set => rayHitText = value;
        }

        /// <summary>
        /// 会被操作的对象字典 方便快速获取场景中需要操作的对象
        /// </summary>
        private Dictionary<string, Behaviour> _opObjects;

        protected override void Awake()
        {
            base.Awake();
            DontDestroyOnLoad(this.gameObject);
            GetAllManager();
        }

        private void Start()
        {
            _opObjects = new Dictionary<string, Behaviour>();
            CurrentScene = ResMagr.CurrentScene;
            UIMagr.m_changePanleWord = ChangePanleWord;
            WordMagr.CurrentLanguagel = defaultLanguagel;
            WordMagr.AddWordChangedEvent(UIMagr.ChangedWord);
            InputMagr.IsEnableInputDevice = isEnableInputDevice;
            InitResConnfig();
            ControllerMagr.InitConfig(role, initXRotate, initYRotate, yMaxAngleLimit, yMinAngleLimit, distance, maxDistance, minDistance,isNeedDamping,dampingTime,moveSpeed,rotateSpeed,scrollWheelSpeed);
            if (isHotfix)
            {
                if (loadMode == UpdateMode.Bulid)
                {
                    if (!string.IsNullOrEmpty(updataHandle))
                    {
                        Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().ToList().Find(p => p.GetType(updataHandle) != null);
                        if (assembly != null)
                            (assembly.CreateInstance(updataHandle) as IUpdataHandle)?.CheckUpdata(StartGame);
                        else
                            Log.Error($"未找到名为【{updataHandle}】的热更入口！");
                    }
                    else
                        Log.Error("请指定一个【IUpdataHandle】类型的热更入口！");
                }
                else
                    StartGame();
            }
            else
                StartGame();
        }

        /// <summary>
        /// 初始化资源配置文件
        /// </summary>
        private void InitResConnfig()
        {
            AssetConfig.AssetBundleManifestName = GetPlatform;
            AssetConfig.RuntimeMode = loadMode;
            resServerUrl = resServerUrl.EndsWith("/") ? resServerUrl : resServerUrl + "/";
            AssetConfig.ResUrl = $"{resServerUrl}{GetPlatform}/";
        }

        void StartGame()
        {
            Type uiType;
            Assembly Csharp;
            if (isHotfix && loadMode != UpdateMode.Editor)
            {
                LoadMetadataForAOTAssemblies();
                byte[] assemblyDll= FileOperations.SafeReadAllBytes(AssetConfig.AssetBundleRootPath + "Assembly-CSharp.dll.bytes");
                if(assemblyDll==null)
                {
                    Log.Error("未加载到Assembly-CSharp.dll.bytes文件，请检查文件是否存在");
                    return;
                }
                Csharp = Assembly.Load(assemblyDll);
            }
            else
                Csharp = AppDomain.CurrentDomain.Load("Assembly-CSharp");
            //进入游戏

            uiType = Csharp.GetType(homePage);
            if (uiType == null)
                Log.Error("请指定一个正确的首界面");
            else
                UIMagr.OpenUI(uiType);
        }

        /// <summary>
        /// 切换语言
        /// </summary>
        /// <param name="arg0"></param>
        /// <returns></returns>
        private string ChangePanleWord(int arg0)
        {
            return WordMagr.GetWord(arg0);
        }

        private void Update()
        {
            OnUpdate?.Invoke();
            InputMagr.OnUpdate();
            ControllerMagr.OnUpdate();
        }

        protected override void OnDestroy()
        {
            base.OnDestroy();
           
        }

        /// <summary>
        /// 实例化所有管理器
        /// </summary>
        private void GetAllManager()
        {
            VersionsdMagr = new VersionsManager(Instance,downloadRoutinneNum);
            ResMagr = new ResourceManager(this,loadMode);
            AudioMagr = new AudioManager(backgroundSource,otherSource);
            WordMagr = new WordManager(languageDate);
            UIMagr = new UIManager(canvas);
            ReferPoolMagr = new ReferencePoolManager();
            DataMagr = new DataManager();
            ObjPoolMagr = new ObjectPoolMananger(objectPool);
            EventMagr = new EventManager();
            WebNetMagr = new WebNetManager(Instance);
            InputMagr = new InputManager(CurrentInputDevice);
            ControllerMagr = new ControllerManager(mainCamera);
        }

        /// <summary>
        /// 延时执行
        /// </summary>
        /// <param name="time"></param>
        /// <param name="action"></param>
        public Coroutine Delay(float time, TAction action) => StartCoroutine(DelayAction(time, action));

        /// <summary>
        /// 延时执行
        /// </summary>
        /// <param name="time"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public IEnumerator DelayAction(float time,TAction action)
        {
            yield return new WaitForSeconds(time);
            action?.Invoke();
        }

        /// <summary>
        /// 持续执行
        /// </summary>
        /// <param name="duration">持续时间</param>
        /// <param name="action">执行事件</param>
        /// <returns></returns>
        public Coroutine Duration(float duration, TAction action) => StartCoroutine(Durations(duration, action));

        public IEnumerator Durations(float duration,TAction action)
        {
            float time = 0;
            while(time<=duration)
            {
                yield return new WaitForFixedUpdate();
                action?.Invoke();
                time += Time.fixedDeltaTime;
            }
        }
        /// <summary>
        /// 为aot assembly加载原始metadata， 这个代码放aot或者热更新都行。
        /// 一旦加载后，如果AOT泛型函数对应native实现不存在，则自动替换为解释模式执行
        /// </summary>
        private static void LoadMetadataForAOTAssemblies()
        {
            List<string> aotMetaAssemblyFiles = new List<string>()
        {
            "mscorlib.dll",
            "System.dll",
            "System.Core.dll",
        };
            /// 注意，补充元数据是给AOT dll补充元数据，而不是给热更新dll补充元数据。
            /// 热更新dll不缺元数据，不需要补充，如果调用LoadMetadataForAOTAssembly会返回错误
            /// 
#if HybridCLR
            HomologousImageMode mode = HomologousImageMode.SuperSet;
            foreach (var aotDllName in aotMetaAssemblyFiles)
            {
                byte[] dllBytes = FileOperations.SafeReadAllBytes(AssetConfig.AssetBundleRootPath+aotDllName + ".bytes");
                // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
                Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
            }
#else
            Log.Error("当前非热更环境！请先安装HybridCLR");
#endif
        }

        /// <summary>
        /// 为其它非Mono类提供Update方法
        /// </summary>
        /// <param name="action"></param>
        public void OnUpdateEvent(TAction action) => OnUpdate += action;

        public void RemoveUpdateEvent(TAction action) => OnUpdate -= action;

        public void RemoveAllUpdateEvent() => OnUpdate = null;

        public void RegisterOpObj(string id,Behaviour behaviour)
        {
            if (!_opObjects.ContainsKey(id))
                _opObjects.Add(id, behaviour);
        }

        public Behaviour GetBehaviour(string id)=> _opObjects.TryGet(id);
    }

    public enum UpdateMode
    {
        Editor,
        Loacl,
        Bulid
    }
}
